package cn.lsj.lock.config;

import cn.lsj.lock.LockAttribute;
import cn.lsj.lock.LockScope;
import cn.lsj.lock.Properties;
import cn.lsj.lock.aop.GlobalLockAspect;
import cn.lsj.lock.core.ReentrantLock;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.*;

import java.util.*;

import static cn.lsj.lock.LockScope.LOCK_SCOPE;


@Configuration
@Import({GlobalLockAspect.class})
public class LockConfiguration implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {


    private cn.lsj.lock.Properties properties;

    private ApplicationContext applicationContext;


    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        loadProperties();

        // 创建锁的的Bean定义信息
        BeanDefinition beanDefinition = createBeanDefinition();

        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();

        beanFactory.registerScope(LOCK_SCOPE, new LockScope());

        for (LockAttribute attribute : properties.getLocks()) {
            // 注册bean定义信息
            registry.registerBeanDefinition(attribute.getLockName(), beanDefinition);
            // 向BeanFactory注册Bean实例
            beanFactory.registerSingleton(attribute.getLockName(), createLock(properties.getDataSource(), attribute));
        }
    }

    /**
     * 加载yml中dataSource和锁的配置信息
     */
    public void loadProperties() {
        Environment environment = applicationContext.getEnvironment();

        DataSource dataSource = getDataSource(environment);
        List<LockAttribute> lockAttributes = new ArrayList<>(getLockAttributesFromEnvironment(environment));

        this.properties = new Properties(dataSource, lockAttributes);
    }

    private DataSource getDataSource(Environment environment) {
        String dataSourceUrl = environment.getProperty("spring.zk.dataSource.url");
        int dataSourcePort = Integer.parseInt(Objects.requireNonNull(environment.getProperty("spring.zk.dataSource.port")));
        return new DataSource(dataSourceUrl, dataSourcePort);
    }

    private ReentrantLock createLock(DataSource dataSource, LockDefinition properties) {
        return new ReentrantLock(dataSource, properties);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 此处可以进行其他的BeanFactory后置处理操作
    }

    private BeanDefinition createBeanDefinition() {
        // 创建Bean定义
        // 这里可以根据需要设置Bean的属性、依赖关系等
        // 示例中直接使用GenericBeanDefinition来创建一个简单的Bean定义
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(ReentrantLock.class);
        beanDefinition.setScope(LOCK_SCOPE);
        return beanDefinition;
    }




    public Set<LockAttribute> getLockAttributesFromEnvironment(Environment environment) {
        ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) environment;
        MutablePropertySources propertySources = configurableEnvironment.getPropertySources();

        String prefix = "spring.zk.locks";
        Set<LockAttribute> lockAttributes = new HashSet<>();

        for (PropertySource<?> propertySource : propertySources) {
            if (propertySource instanceof EnumerablePropertySource) {
                EnumerablePropertySource<?> enumerablePropertySource = (EnumerablePropertySource<?>) propertySource;
                String[] propertyNames = enumerablePropertySource.getPropertyNames();
                for (String propertyName : propertyNames) {
                    if (propertyName.startsWith(prefix)) {
                        LockAttribute lockAttribute = parseLockAttribute(propertyName, environment, prefix);
                        lockAttributes.add(lockAttribute);
                    }
                }
            }
        }

        return lockAttributes;
    }


    /**
     * 解析属性名，提取出zkPath、lockName、timeout等属性的值
     */
    private LockAttribute parseLockAttribute(String propertyName, Environment environment, String prefix) {
        // 解析属性名，提取索引信息
        String index = extractIndexFromPropertyName(propertyName);

        // 根据索引信息，获取对应的属性值
        String zkPath = environment.getProperty(prefix + index + ".zkPath");
        String lockName = environment.getProperty(prefix + index + ".lockName");
        String timeout = environment.getProperty(prefix + index + ".timeout");

        // 创建并返回LockAttribute对象
        LockAttribute lockAttribute = new LockAttribute();
        lockAttribute.setZkPath(zkPath);
        lockAttribute.setLockName(lockName);
        assert timeout != null;
        lockAttribute.setTimeout(Integer.parseInt(timeout));
        return lockAttribute;
    }

    // 提取属性名中的索引信息
    private String extractIndexFromPropertyName(String propertyName) {
        int startIndex = propertyName.indexOf("[");
        int endIndex = propertyName.indexOf("]");
        if (startIndex != -1 && endIndex != -1 && endIndex > startIndex) {
            return propertyName.substring(startIndex, endIndex + 1);
        }
        return "";
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }


}
